package com.ttx.rabbitmq.demo.config;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.AsyncRabbitTemplate;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * https://www.rabbitmq.com/getstarted.html
 *
 * <p>RabbitMQ is a message broker: it accepts and forwards messages.
 * You can think about it as a post office: when you put the mail that you want posting in a post box,
 * you can be sure that Mr. or Ms. Mailperson will eventually deliver the mail to your recipient.
 * In this analogy, RabbitMQ is a post box, a post office and a postman. </p>
 *
 * RabbitMQ是一个消息代理: 用于接收和分发消息
 *
 *
 * @author TimFruit
 * @date 20-1-10 下午6:13
 */
@Configuration
public class RabbitMqConfig {


    @Bean("defaultRabbitTemplate")
    public RabbitTemplate defaultRabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate=new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }



    // ===================================
    // https://www.rabbitmq.com/tutorials/tutorial-two-java.html
    // 1. 工作队列 -- 用作缓冲队列,  mq推送一条消息到一个消费端, 多个消费端可以并行执行不同消息
    // Manual message acknowledgments are turned on by default
    // 正常处理完一条消息后, 发送ack给mq, mq可以"自由"删除该消息,
    // 如果没有收到ack, mq会认为对应消费端出问题了, 然后发送该消息给其他正常的消费端

    //使用默认的exchange(""), routing_key为队列名

    public static final String WORK_QUEUE_NAME ="work.queue";

    // 由RabbitAdmin收集队列信息, 并注入Connection监听器
    // 创建connection后, 会声明(创建)队列
    @Bean
    public Queue workQueue(){
        Queue queue=new Queue(WORK_QUEUE_NAME, true, false, false);
        return queue;
    }


    // ===================================
    // https://www.rabbitmq.com/tutorials/tutorial-three-java.html
    // 2. 发布-订阅 发送一样的消息到多个队列
    public static final String PUBLISH_SUBSCRIBE_LOGS_EXCHANGE_NAME="publish.subscribe.logs.exchange";
    public static final String PUBLISH_SUBSCRIBE_LOGS_QUEUE_NAME_1="publish.subscribe.logs.queue.1";
    public static final String PUBLISH_SUBSCRIBE_LOGS_QUEUE_NAME_2="publish.subscribe.logs.queue.2";
    public static final String PUBLISH_SUBSCRIBE_LOGS_ROUTING_KEY=""; //路由key为空

    @Bean
    public Exchange logsExchange(){
        // 类型为fanout 无脑广播 (Sending messages to many consumers at once)
        Exchange exchange=new FanoutExchange(PUBLISH_SUBSCRIBE_LOGS_EXCHANGE_NAME);
        return exchange;
    }

    @Bean
    public Queue logsQueue1(){
        Queue queue=new Queue(PUBLISH_SUBSCRIBE_LOGS_QUEUE_NAME_1);
        return  queue;
    }

    @Bean
    public Binding logsBinding1(){
        Binding binding=new Binding(
                PUBLISH_SUBSCRIBE_LOGS_QUEUE_NAME_1,
                Binding.DestinationType.QUEUE,
                PUBLISH_SUBSCRIBE_LOGS_EXCHANGE_NAME,
                PUBLISH_SUBSCRIBE_LOGS_ROUTING_KEY,
                null);
        return binding;
    }

    @Bean
    public Queue logsQueue2(){
        Queue queue=new Queue(PUBLISH_SUBSCRIBE_LOGS_QUEUE_NAME_2);
        return queue;
    }

    @Bean
    public Binding logsBinding2(){
        Binding binding=new Binding(PUBLISH_SUBSCRIBE_LOGS_QUEUE_NAME_2,
                Binding.DestinationType.QUEUE,PUBLISH_SUBSCRIBE_LOGS_EXCHANGE_NAME,
                PUBLISH_SUBSCRIBE_LOGS_ROUTING_KEY,
                null);
        return binding;
    }


    // ===================================
    // https://www.rabbitmq.com/tutorials/tutorial-four-java.html
    // 3. 路由 根据完全匹配routing_key发送消息到指定queue
    public static final String ROUTE_COLOR_EXCHANGE_NAME="route.color.exchange";

    public static final String ROUTE_COLOR_BLUE_QUEUE_NAME="route.color.blue.queue";
    public static final String ROUTE_COLOR_BLUE_ROUTING_KEY="blue";

    public static final String ROUTE_COLOR_BLACK_QUEUE_NAME_1="route.color.black.queue.1";
    public static final String ROUTE_COLOR_BLACK_QUEUE_NAME_2="route.color.black.queue.2";
    public static final String ROUTE_COLOR_BLACK_ROUTING_KEY="black";


    @Bean
    public Exchange colorExchange(){
        // 类型为direct 根据完全匹配routing_key发送消息到指定queue (Receiving messages selectively)
        Exchange exchange=new DirectExchange(ROUTE_COLOR_EXCHANGE_NAME);
        return exchange;
    }

    @Bean
    public Queue blueQueue(){
        Queue queue=new Queue(ROUTE_COLOR_BLUE_QUEUE_NAME);
        return  queue;
    }

    //构建binding, 将route_key和对应queue绑定在一次，类似构建路由表，使得exchange能够根据route_key分发消息到对应队列里
    @Bean
    public Binding blueBinding(){
        Binding binding=new Binding(
                ROUTE_COLOR_BLUE_QUEUE_NAME,
                Binding.DestinationType.QUEUE,
                ROUTE_COLOR_EXCHANGE_NAME,
                ROUTE_COLOR_BLUE_ROUTING_KEY,
                null);
        return binding;
    }

    @Bean
    public Queue blackQueue1(){
        Queue queue=new Queue(ROUTE_COLOR_BLACK_QUEUE_NAME_1);
        return  queue;
    }

    @Bean
    public Binding blackBinding1(){
        Binding binding=new Binding(
                ROUTE_COLOR_BLACK_QUEUE_NAME_1,
                Binding.DestinationType.QUEUE,
                ROUTE_COLOR_EXCHANGE_NAME,
                ROUTE_COLOR_BLACK_ROUTING_KEY,
                null);
        return binding;
    }

    @Bean
    public Queue blackQueue2(){
        Queue queue=new Queue(ROUTE_COLOR_BLACK_QUEUE_NAME_2);
        return  queue;
    }

    @Bean
    public Binding blackBinding2(){
        Binding binding=new Binding(
                ROUTE_COLOR_BLACK_QUEUE_NAME_2,
                Binding.DestinationType.QUEUE,
                ROUTE_COLOR_EXCHANGE_NAME,
                ROUTE_COLOR_BLACK_ROUTING_KEY,
                null);
        return binding;
    }


    // ===================================
    // https://www.rabbitmq.com/tutorials/tutorial-five-java.html
    // 4. 匹配符模糊匹配 可以根据匹配符模糊匹配routing_key, 发送到对应的queue

    public static final String TOPIC_LOGS_EXCHANGE_NAME="topic.logs.exchange";

    // routing_key 以"."分隔, "."之间的所有字母为一个单词
    // "#"可以匹配0个或多个单词
    // "*"仅匹配一个单词
    public static final String TOPIC_LOGS_WHOLE_QUEUE_NAME="topic.logs.whole.queue";
    public static final String TOPIC_LOGS_WHOLE_ROUTING_KEY="#";

    public static final String TOPIC_LOGS_KERN_ALL_QUEUE_NAME="topic.logs.kern.all.queue";
    public static final String TOPIC_LOGS_KERN_ALL_ROUTING_KEY="kern.*";

    public static final String TOPIC_LOGS_ALL_CRITICAL_QUEUE_NAME="topic.logs.all.critical.queue";
    public static final String TOPIC_LOGS_ALL_CRITICAL_ROUTING_KEY="*.critical";

    public static final String TOPIC_LOGS_KERN_CRITICAL_QUEUE_NAME="topic.logs.kern.critical.queue";
    public static final String TOPIC_LOGS_KERN_CRITICAL_ROUTING_KEY="kern.critical";

    @Bean
    public Exchange topicLogsExchange(){
        // 类型为topic 可以根据匹配符模糊匹配routing_key, 发送到对应的queue
        Exchange exchange=new TopicExchange(TOPIC_LOGS_EXCHANGE_NAME);
        return exchange;
    }

    @Bean
    public Queue wholeQueue(){
        Queue queue=new Queue(TOPIC_LOGS_WHOLE_QUEUE_NAME);
        return  queue;
    }

    @Bean
    public Binding wholeBinding(){
        Binding binding=new Binding(
                TOPIC_LOGS_WHOLE_QUEUE_NAME,
                Binding.DestinationType.QUEUE,
                TOPIC_LOGS_EXCHANGE_NAME,
                TOPIC_LOGS_WHOLE_ROUTING_KEY,
                null);
        return binding;
    }

    @Bean
    public Queue kernAllQueue(){
        Queue queue=new Queue(TOPIC_LOGS_KERN_ALL_QUEUE_NAME);
        return  queue;
    }

    @Bean
    public Binding kernAllBinding(){
        Binding binding=new Binding(
                TOPIC_LOGS_KERN_ALL_QUEUE_NAME,
                Binding.DestinationType.QUEUE,
                TOPIC_LOGS_EXCHANGE_NAME,
                TOPIC_LOGS_KERN_ALL_ROUTING_KEY,
                null);
        return binding;
    }

    @Bean
    public Queue allCriticalQueue(){
        Queue queue=new Queue(TOPIC_LOGS_ALL_CRITICAL_QUEUE_NAME);
        return  queue;
    }

    @Bean
    public Binding allCriticalBinding(){
        Binding binding=new Binding(
                TOPIC_LOGS_ALL_CRITICAL_QUEUE_NAME,
                Binding.DestinationType.QUEUE,
                TOPIC_LOGS_EXCHANGE_NAME,
                TOPIC_LOGS_ALL_CRITICAL_ROUTING_KEY,
                null);
        return binding;
    }

    @Bean
    public Queue kernCriticalQueue(){
        Queue queue=new Queue(TOPIC_LOGS_KERN_CRITICAL_QUEUE_NAME);
        return  queue;
    }

    @Bean
    public Binding kernCriticalBinding(){
        Binding binding=new Binding(
                TOPIC_LOGS_KERN_CRITICAL_QUEUE_NAME,
                Binding.DestinationType.QUEUE,
                TOPIC_LOGS_EXCHANGE_NAME,
                TOPIC_LOGS_KERN_CRITICAL_ROUTING_KEY,
                null);
        return binding;
    }




}
